#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import os

from ctools.converters.convbase import NConverterBase
from ctools.ly_parser.nodes import *
from ctools.converters.conv_kn import ConvKeepN2Gv
from ctools.converters.conv_fn import ConvFuncN2Gv
from ctools.converters.conv_ctn import ConvCTN2Gv
from ctools.common.strhelper import *
from ctools.common.paramconfig import ParamDesc, ParamConfig

from ctools.logext import *
import logging

_rlog, _plog, _mlog, _tlog = get_loggers(__file__, __name__, propagate=False)

config_params = {
    "MODE"              : "tailport",
    "NODE_COLOR_MIN"    : 180,
    "NODE_COLOR_MAX"    : 230,
    "EDGE_COLOR_MIN"    : 10,
    "EDGE_COLOR_MAX"    : 150,
    "CLUSTER_COLOR_MIN" : 230,
    "CLUSTER_COLOR_MAX" : 250,
    "gvtext"            : "",
    "graph_strict"      : False,
    "funcpointer_mode"  : "name",
}

def _gen_paramconfig(fileversion=None):
    paramcfg = ParamConfig(fileversion)
    paramcfg.add_descs((
        ParamDesc("gvtext",             "",             20231127),
        ParamDesc("graph_strict",       "false",        20240808),
        ParamDesc("funcpointer_mode",   "name",         20241025),
        ParamDesc("render_mode",        "default",      20241106),
    ))
    return paramcfg


class ConvN2Param(NConverterBase):
    def _process_paramnode(self, node, args=None, depth=0):
        if not isinstance(node, ParamNode):
            return

        args[node.name] = node.value.strip('"')

    def process(self, treenode:Node):
        paramcfg = _gen_paramconfig()
        for node in treenode:
            self._process_paramnode(node, args=paramcfg)

        paramcfg._fileversion = paramcfg.get_int('template_date')
        return paramcfg

    def convert(self, treenode:Node):
        return self.process(treenode)


# With the help of the local variables of the class,
# the processing function of iter_nodes can be simple.
class ConvN2Gv(NConverterBase):
    def __init__(self, paramcfg:ParamConfig={}):
        self.keep_gen = ConvKeepN2Gv()
        self.reset(paramcfg)

    def reset(self, paramcfg:ParamConfig):
        # TODO: remove self._paramcfg
        self._paramcfg = paramcfg
        self._text = ''

        self.typedecls = dict()
        self.typealiases = dict()

        self.funcs = {}

    def _process_type_node(self, node, args=None, depth=0):
        if isinstance(node, TypeNode):
            self.typedecls[node.typename] = node

        if isinstance(node, AliasNode):
            self.typealiases[node.name] = node.target

    def _process_funcnode(self, node, args=None, depth=0):
        if not isinstance(node, FuncNode):
            return
        self.funcs[node.name] = node

    def _process_keepnode(self, node, args=None, depth=0):
        if not isinstance(node, KeepNode):
            return
        self._text += self.keep_gen.process(node, indent=0) + '\n'

    def _process_funcnode_and_keepnode(self, node, args=None, depth=0):
        if isinstance(node, KeepNode):
            self._process_keepnode(node, args, depth)
        elif isinstance(node, FuncNode):
            if node.name != 'main':
                return
            proc = ConvFuncN2Gv(self.typedecls, self.typealiases,
                                    self._paramcfg, self.funcs)
            self._text += proc.process(node)
        elif isinstance(node, CTreeNode):
            conv = ConvCTN2Gv()
            text = indent_str(1, conv.convert(node))
            self._text += text + '\n'

    def process(self, treenode:Node):
        self._text = 'digraph "" {\n'

        for node in treenode:
            self._process_type_node(node)
            self._process_funcnode(node)

        for node in treenode:
            self._process_funcnode_and_keepnode(node)

        self._text += '}\n'

        return self._text

    def convert(self, treenode:Node):
        return self.process(treenode)

class ConvGv2N(NConverterBase):
    pass

class ConvN2C(NConverterBase):
    pass


class ConvC2N(NConverterBase):
    pass
